import java.lang.management.*;
import java.lang.ref.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class GarbageCollectionApplication {
    // 用于演示强引用
    private static List<Object> strongReferences = new ArrayList<>();

    public static void main(String[] args) {
        // 1. GC信息监控
        //gcMonitoringDemo();

        // 2. 引用类型演示
        //referenceTypesDemo();

        // 3. 分代收集演示
        //generationalGCDemo();

        // 4. GC算法演示
        //gcAlgorithmDemo();

        // 5. 内存泄漏演示
        memoryLeakDemo();
    }

    /**
     * GC信息监控演示
     */
    private static void gcMonitoringDemo() {
        System.out.println("=== GC信息监控演示 ===");

        // 获取所有垃圾收集器
        List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();

        System.out.println("当前JVM使用的垃圾收集器:");
        for (GarbageCollectorMXBean gcBean : gcBeans) {
            System.out.println("  收集器名称: " + gcBean.getName());
            System.out.println("  管理的内存池: " + Arrays.toString(gcBean.getMemoryPoolNames()));
            System.out.println("  收集次数: " + gcBean.getCollectionCount());
            System.out.println("  收集时间: " + gcBean.getCollectionTime() + "ms");
            System.out.println();
        }

        // 记录GC前的状态
        long beforeGCCount = getTotalGCCount();
        long beforeGCTime = getTotalGCTime();

        // 创建大量对象触发GC
        List<byte[]> tempList = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            tempList.add(new byte[1024 * 100]); // 100KB对象
        }

        // 手动触发GC
        System.gc();

        try {
            Thread.sleep(1000); // 等待GC完成
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // 记录GC后的状态
        long afterGCCount = getTotalGCCount();
        long afterGCTime = getTotalGCTime();

        System.out.println("GC统计信息:");
        System.out.println("  GC次数增加: " + (afterGCCount - beforeGCCount));
        System.out.println("  GC时间增加: " + (afterGCTime - beforeGCTime) + "ms");

        // 清理临时对象
        tempList.clear();

        System.out.println();
    }

    /**
     * 引用类型演示
     */
    private static void referenceTypesDemo() {
        System.out.println("=== 引用类型演示 ===");

        // 1. 强引用 (Strong Reference)
        Object strongRef = new Object();
        System.out.println("强引用对象: " + strongRef);

        // 2. 软引用 (Soft Reference) - 内存不足时回收
        Object softObject = new Object();
        SoftReference<Object> softRef = new SoftReference<>(softObject);
        softObject = null; // 移除强引用

        System.out.println("软引用对象 (GC前): " + softRef.get());
        System.gc();
        System.out.println("软引用对象 (GC后): " + softRef.get());

        // 3. 弱引用 (Weak Reference) - GC时回收
        Object weakObject = new Object();
        WeakReference<Object> weakRef = new WeakReference<>(weakObject);
        weakObject = null; // 移除强引用

        System.out.println("弱引用对象 (GC前): " + weakRef.get());
        System.gc();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("弱引用对象 (GC后): " + weakRef.get());

        // 4. 虚引用 (Phantom Reference) - 用于跟踪对象回收
        Object phantomObject = new Object();
        ReferenceQueue<Object> queue = new ReferenceQueue<>();
        PhantomReference<Object> phantomRef = new PhantomReference<>(phantomObject, queue);

        System.out.println("虚引用对象: " + phantomRef.get()); // 总是返回null
        phantomObject = null;
        System.gc();

        try {
            Thread.sleep(100);
            Reference<?> ref = queue.poll();
            if (ref != null) {
                System.out.println("虚引用对象已被回收，收到通知");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        System.out.println();
    }

    /**
     * 分代收集演示
     */
    private static void generationalGCDemo() {
        System.out.println("=== 分代收集演示 ===");

        // 获取内存池信息
        List<MemoryPoolMXBean> memoryPools = ManagementFactory.getMemoryPoolMXBeans();

        System.out.println("分代内存使用情况:");
        for (MemoryPoolMXBean pool : memoryPools) {
            if (pool.getType() == MemoryType.HEAP) {
                MemoryUsage usage = pool.getUsage();
                System.out.println("  " + pool.getName() + ":");
                System.out.println("    已使用: " + formatBytes(usage.getUsed()));
                System.out.println("    最大值: " + formatBytes(usage.getMax()));
                System.out.println("    使用率: " + String.format("%.2f%%",
                        (double) usage.getUsed() / usage.getCommitted() * 100));
            }
        }

        // 演示对象在新生代的分配
        System.out.println("\n创建短生命周期对象 (新生代):");
        List<String> shortLivedObjects = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            shortLivedObjects.add("短生命周期对象" + i);
        }

        printMemoryUsage("创建短生命周期对象后");

        // 清理短生命周期对象
        shortLivedObjects.clear();
        System.gc();

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        printMemoryUsage("清理短生命周期对象后");

        // 演示对象晋升到老年代
        System.out.println("\n创建长生命周期对象 (可能晋升到老年代):");
        for (int i = 0; i < 1000; i++) {
            strongReferences.add("长生命周期对象" + i);
        }

        // 触发多次GC，促使对象晋升
        for (int i = 0; i < 5; i++) {
            System.gc();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        printMemoryUsage("创建长生命周期对象并多次GC后");

        System.out.println();
    }

    /**
     * GC算法演示
     */
    private static void gcAlgorithmDemo() {
        System.out.println("=== GC算法演示 ===");

        // 演示不同场景下的GC行为

        // 1. 大量小对象 - 适合复制算法
        System.out.println("1. 大量小对象分配 (新生代复制算法):");
        long startTime = System.currentTimeMillis();
        List<Object> smallObjects = new ArrayList<>();

        for (int i = 0; i < 100000; i++) {
            smallObjects.add(new Object());
        }

        long allocTime = System.currentTimeMillis() - startTime;
        System.out.println("  分配10万个小对象耗时: " + allocTime + "ms");

        startTime = System.currentTimeMillis();
        smallObjects.clear();
        System.gc();
        long gcTime = System.currentTimeMillis() - startTime;
        System.out.println("  清理并GC耗时: " + gcTime + "ms");

        // 2. 少量大对象 - 可能直接进入老年代
        System.out.println("\n2. 少量大对象分配 (可能直接进入老年代):");
        startTime = System.currentTimeMillis();
        List<byte[]> largeObjects = new ArrayList<>();

        for (int i = 0; i < 100; i++) {
            largeObjects.add(new byte[1024 * 1024]); // 1MB对象
        }

        allocTime = System.currentTimeMillis() - startTime;
        System.out.println("  分配100个大对象(1MB)耗时: " + allocTime + "ms");

        startTime = System.currentTimeMillis();
        largeObjects.clear();
        System.gc();
        gcTime = System.currentTimeMillis() - startTime;
        System.out.println("  清理并GC耗时: " + gcTime + "ms");

        // 3. 混合场景
        System.out.println("\n3. 混合场景 (小对象+大对象):");
        startTime = System.currentTimeMillis();
        List<Object> mixedObjects = new ArrayList<>();

        for (int i = 0; i < 10000; i++) {
            if (i % 100 == 0) {
                mixedObjects.add(new byte[1024 * 100]); // 100KB大对象
            } else {
                mixedObjects.add(new Object()); // 小对象
            }
        }

        allocTime = System.currentTimeMillis() - startTime;
        System.out.println("  混合分配耗时: " + allocTime + "ms");

        startTime = System.currentTimeMillis();
        mixedObjects.clear();
        System.gc();
        gcTime = System.currentTimeMillis() - startTime;
        System.out.println("  清理并GC耗时: " + gcTime + "ms");

        System.out.println();
    }

    /**
     * 内存泄漏演示
     */
    private static void memoryLeakDemo() {
        System.out.println("=== 内存泄漏演示 ===");

        // 1. 静态集合导致的内存泄漏
        System.out.println("1. 静态集合内存泄漏演示:");
        printMemoryUsage("添加到静态集合前");

        for (int i = 0; i < 10000; i++) {
            strongReferences.add("泄漏对象" + i);
        }

        printMemoryUsage("添加到静态集合后");

        // 即使手动GC，静态集合中的对象也不会被回收
        System.gc();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        printMemoryUsage("GC后 (对象仍然存在)");

        // 2. 监听器未移除导致的内存泄漏
        System.out.println("\n2. 监听器内存泄漏演示:");
        EventSource eventSource = new EventSource();

        for (int i = 0; i < 1000; i++) {
            EventListener listener = new EventListener("监听器" + i);
            eventSource.addListener(listener);
            // 注意：这里没有移除监听器，会导致内存泄漏
        }

        System.out.println("  添加了1000个监听器");
        System.out.println("  事件源持有的监听器数量: " + eventSource.getListenerCount());

        // 3. 内存泄漏的解决方案
        System.out.println("\n3. 内存泄漏解决方案:");

        // 清理静态集合
        int beforeSize = strongReferences.size();
        strongReferences.clear();
        System.out.println("  清理静态集合: " + beforeSize + " -> " + strongReferences.size());

        // 清理监听器
        eventSource.clearListeners();
        System.out.println("  清理监听器: " + eventSource.getListenerCount() + "个");

        System.gc();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        printMemoryUsage("清理内存泄漏后");

        System.out.println();
    }

    // 辅助方法
    private static long getTotalGCCount() {
        long total = 0;
        for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) {
            total += gcBean.getCollectionCount();
        }
        return total;
    }

    private static long getTotalGCTime() {
        long total = 0;
        for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) {
            total += gcBean.getCollectionTime();
        }
        return total;
    }

    private static void printMemoryUsage(String phase) {
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();

        System.out.println("  " + phase + " - 堆内存: " +
                formatBytes(heapUsage.getUsed()) + " / " +
                formatBytes(heapUsage.getMax()));
    }

    private static String formatBytes(long bytes) {
        if (bytes < 0) return "N/A";

        String[] units = {"B", "KB", "MB", "GB"};
        int unitIndex = 0;
        double size = bytes;

        while (size >= 1024 && unitIndex < units.length - 1) {
            size /= 1024;
            unitIndex++;
        }

        return String.format("%.2f %s", size, units[unitIndex]);
    }
}

/**
 * 事件源类 - 用于演示监听器内存泄漏
 */
class EventSource {
    private List<EventListener> listeners = new ArrayList<>();

    public void addListener(EventListener listener) {
        listeners.add(listener);
    }

    public void removeListener(EventListener listener) {
        listeners.remove(listener);
    }

    public void clearListeners() {
        listeners.clear();
    }

    public int getListenerCount() {
        return listeners.size();
    }
}

/**
 * 事件监听器类
 */
class EventListener {
    private String name;
    private byte[] data = new byte[1024]; // 占用一些内存

    public EventListener(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "EventListener{name='" + name + "'}";
    }
}
